package server.auction;

/**
 * This class represents a server-thread from the auction-service
 * that accepts connections with the clients. For each
 * client there will be started another thread for request handling (ServerCommandHandlerThread)
 * This thread (ServerAcceptConnectionsThread) will be started only once.
 *
 * @version 1.0 vom 19.10.2012
 * @author Peter Tillian 1026312
 */

import java.io.IOException;
import java.net.ServerSocket;
import java.security.PrivateKey;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.ArrayList;

import model.*;

public class AuctionServerAcceptConnectionsThread extends Thread {
	private int tcpPort;
	private ServerSocket serverSocket;
	private ExecutorService serverExecutor;
	private ArrayList<AuctionServerCommandHandlerThread> commandHandlers;
	private String analyticsName;
	private String billingName;
	private String keyDirClient;
	private String registryHost;
	private PrivateKey keyServer;
	private int registryPort;

	public AuctionServerAcceptConnectionsThread(int tcpPort,
			String analyticsName, String billingName, PrivateKey keyServer,
			String keyDirClient, String registryHost, int registryPort) {
		super("ServerAcceptConnectionsThread");
		this.tcpPort = tcpPort;
		this.commandHandlers = new ArrayList<AuctionServerCommandHandlerThread>();
		this.analyticsName = analyticsName;
		this.billingName = billingName;
		this.registryHost = registryHost;
		this.registryPort = registryPort;
		this.keyServer = keyServer;
		this.keyDirClient = keyDirClient;
	}

	public void run() {
		serverExecutor = Executors.newCachedThreadPool();
		// creating a serverSocket an listen at specific port. (bind)
		try {
			serverSocket = new ServerSocket(tcpPort);
		} catch (IOException e) {
			System.err.println("Error, could not listen on port: " + tcpPort
					+ ". " + e.getMessage());
			this.serverExecutor.shutdownNow();
			System.exit(1);
		}

		// accepting connections from client and start new thread for each
		// client.
		while (true) {
			try {
				// if this thread is interrupted while not in a blocked-state.
				if (this.isInterrupted()) {
					this.interrupt();
				}
				AuctionServerCommandHandlerThread sch = new AuctionServerCommandHandlerThread(
						serverSocket.accept(), analyticsName, billingName,
						keyServer, keyDirClient, registryHost, registryPort);
				this.commandHandlers.add(sch);
				serverExecutor.execute(sch); // start threads with
												// executor-service
				System.out.println("Client connected.");
			} catch (IOException e) {
				if (!serverSocket.isClosed()) {
					System.err.println("Accept failed on port: " + tcpPort
							+ ". " + e.getMessage());
				} else {
					serverExecutor.shutdownNow();
					for (AuctionServerCommandHandlerThread handler : commandHandlers) {
						try { // close all ServerCommandHandlerThreads
								// (socket.close())
							handler.channel.close();
						} catch (IOException e2) {
							if (!handler.channel.isClosed()) {
								System.err.println("Error closing socket in "
										+ handler.getName() + " "
										+ handler.getId() + ": "
										+ e2.getMessage());
							}
						}
					}
					ObjectManagementPool.getInstance().cancelAllTimers(); // cancel
																			// all
																			// running
																			// auctions.
					for (Auction a : ObjectManagementPool.getInstance()
							.getCurrentAuctions()) {
						a.cancel();
					}
					for (User u : ObjectManagementPool.getInstance()
							.getCurrentUsers()) { // logout all users.
						u.logout();
					}
					break;
				}
			}
		}
	} // end run()

	@Override
	public void interrupt() {
		try {
			this.serverSocket.close();
		} catch (IOException e) {
			System.err.println("Error closing ServerSocket in "
					+ this.getClass() + ": " + e.getMessage());
		}
		super.interrupt();
	}
} // end of class ServerAcceptConnectionsThread
